import { getToken } from './auth'
import { convertObj2KV } from './util.js'

const SOCKET_CMD = {
  // 登录成功
  login: 2,
  // 聊天消息
  message: 3,
  // 事件
  event: 4,
  // 心跳
  heartbeat: 6,
  // 错误
  error: 11
}

export default class SocketService {
  // 用于实现单例模式的写法
  // 可以确保在整个应用程序中只有一个SocketService实例存在，避免了多次实例化和重复连接服务器的问题。通过单例模式，可以方便地在应用程序的不同模块中共享同一个SocketService实例，实现统一的数据传输和处理逻辑。
  static instance = null;
  static get Instance() {
    if (!this.instance) {
      this.instance = new SocketService()
    }
    return this.instance
  }
  ws = null
  heartbeatInterval = null
  // 标识是否连接成功
  connected = false
  // 重试的次数
  sendRetryCount = 0
  // 重连的次数
  connectRetryCount = 0
  // 未发送的消息队列
  msgQueue = []

  client = 'yoyo-meeting-uni-1.0.0'
  // ws链接地址
  socketUrl = ''
  // 会议ID
  meetingId = ''
  // 是否在会议中，会议中断开socket要进行重连
  isInMeeting = false
  // 当前用户进入房间时间
  serverTime = 0

  constructor() {
    const { appEnv, deviceId } = getApp({allowDefault: true}).globalData;
    // TODO 设备ID
    this.deviceId = deviceId || 'web_device00001'
    this.wsDomain = appEnv === 'prod' 
      ? 'cloudmeeting.quanyou.com.cn:8319' // 生产
      : 'cloudmeetingcs.quanyou.com.cn:8319' // 测试
    this.token = getToken()
  }

  init(meetingId, isInnerNet=false) {
    this.setUrl(meetingId, isInnerNet)
    this.connect()
    this.isInMeeting = true
  }
  
  // 构造ws链接
  setUrl(meetingId, isInner) {
    this.meetingId = meetingId
    const urlParams = {
      token: this.token,
      client: this.client,
      deviceId: this.deviceId,
      meetingId: meetingId,
      isInner: isInner ? 'Y' : 'N'
    };
    this.socketUrl = `ws://${this.wsDomain}/?${convertObj2KV(urlParams)}`
  }
  
  setServerTime(time) {
    this.serverTime = time
  }
  
  // 连接服务器的方法
  connect() {
    // this.ws = new WebSocket(this.socketUrl);
    console.log('socketUrl:', this.socketUrl)
    // 经验证，通过返回SocketTask监听不到事件
    uni.connectSocket({
      url: this.socketUrl,
      success: () => {
        // console.log('初始化websocket成功')
      },
      fail: () => {
        console.log('初始化websocket失败')
      },
      complete: () => {}
    });
    
    uni.onSocketOpen((res) => {
      // uni.showToast({
      //   title: 'socket已连接',
      //   icon: 'none',
      //   duration: 1500
      // })
      
      console.log('WebSocket连接已打开！');
      this.connected = true;
      this.connectRetryCount = 0;
      clearTimeout(this.heartbeatInterval);
      this.start();
      
      // 连接成功后发送队列中的消息
      // for (let i = 0; i < this.msgQueue.length; i++) {
      //   this.send(this.msgQueue[i])
      // }
      // this.msgQueue = [];
    });
    
    uni.onSocketError((res) => {
      // 断网后会进入
      console.log('WebSocket连接打开失败，请检查！', JSON.stringify(res));
      // uni.showToast({
      //   title: 'socket连接失败',
      //   icon: 'none',
      //   duration: 1500
      // })
      
      if (!this.isInMeeting) {
        return
      }
      
      // 断网后重置进房时间
      this.setServerTime(0)
      this.connected = false;
      if (this.connectRetryCount <= 100) {
        setTimeout(() => {
          this.connectRetryCount++
          this.connect()
        }, 3000)
      } else {
        uni.showModal({
          title: '提示',
          content: '请检查网络后重新进入会议',
          showCancel: false
        });
      }
    });
    
    uni.onSocketClose((res) => {
      console.log('WebSocket 已关闭！');
      this.connected = false;
    });
    
    uni.onSocketMessage((res) => {
      // 处理不同类型的消息
      // property {cmd} 返回类型
      // LOGIN(2, LoginReqHandler.class) //  登录成功
      // MESSAGE(3, ChatReqHandler.class) // 聊天消息
      // EVENT(4,null) // 事件通知
      // HEARTBEAT(6, HeartbeatHandler.class) // 心跳请求
      // SYSTEM_MESSAGE(7,null) // 系统消息
      // SEND_MESSAGE_FAIL(9,null)
      // ERROR(11, null) // 错误
      
      // property {type} 返回类型
      // REMOVE_USER(0, "移除用户"), // 用不上
      // CLIENT_QUIT(1, "用户客户端退出"), // 用不上
      // DISMISS_ROOM(2, "解散房间"),
      // MODIFY_SETTING(3, "修改会议配置"),
      // MODIFY_MSG_SETTING(4, "修改用户发消息配置"),
      // RECALL_MSG(5, "用户撤回消息"),
      // MEETING_CONTINUE(6, "提醒主持人会议是否延续"), 
      
      const socketRes = JSON.parse(res.data);
      
      if (socketRes.cmd != SOCKET_CMD.heartbeat) {
        console.log('socket响应：' + res.data);
      }
      
      switch (socketRes.cmd) {
        case SOCKET_CMD.login:
          uni.$emit('socket-login', socketRes);
          break;
        case SOCKET_CMD.heartbeat:
          uni.$emit('socket-heartbeat');
          break;
        case SOCKET_CMD.event:
          uni.$emit('socket-event', socketRes);
          break; 
        case SOCKET_CMD.message:
          uni.$emit('socket-msg', socketRes);
          break; 
        case SOCKET_CMD.error:
          uni.$emit('socket-error', socketRes);
          break; 
      }
    });
  }
  
  // 发送
  send(msgData) {
    if (this.connected) {
      uni.sendSocketMessage({
        data: JSON.stringify(msgData)
      });
    } else {
      // this.msgQueue.push(msgData)
    }
  }
  
  // 关闭socket连接
  close() {
    this.isInMeeting = false;
    if (this.connected) {
      console.log('关闭socket连接');
      uni.closeSocket();
      this.connected = false; // 更新连接状态
    }
    clearInterval(this.heartbeatInterval); // 清除心跳检测定时器
  }
  
  // 开启心跳检测
  start() {
    this.heartbeatInterval = setInterval(() => {
      // console.log('heatbeat:', Date.now())
      this.send({
        "cmd": SOCKET_CMD.heartbeat,
        "t": Date.now()
      });
    }, 3000);
  }
}